﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Threading;
using System.Windows.Controls;


namespace ImageProcessing
{
    // Линейные преобразования.
    public static class LfpOperations
    {
        public static EventHandler<ProgressValueEventArgs> ProgressChangeEventHandler;
        const int Plen = 4;
        // IIF
        public static void Iif(int height, int width, List<int> mask, WriteableBitmap image)
        {
            var halfHeight = height/2;
            var halfWidth = width/2;
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = halfHeight; i < image.PixelHeight-halfHeight; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new  ProgressValueEventArgs((double)i / (double)(image.PixelHeight - halfHeight)));
                for (var j = halfWidth; j < image.PixelWidth-halfWidth; j++)
                {
                    var r = 0;
                    var g = 0;
                    var b = 0;
                    for (var k = i-halfHeight; k <= i+halfHeight; k++)
                    {
                        for (var n = j-halfWidth; n <= j+halfWidth; n++)
                        {
                            r += mask[(k - i + halfHeight) * width + (n - j + halfWidth)] * pixels[k * image.PixelWidth * Plen + n * Plen];
                            g += mask[(k - i + halfHeight) * width + (n - j + halfWidth)] * pixels[k * image.PixelWidth * Plen + n * Plen + 1];
                            b += mask[(k - i + halfHeight) * width + (n - j + halfWidth)] * pixels[k * image.PixelWidth * Plen + n * Plen + 2];
                        }
                    }
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, r));
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, g));
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, b));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult, image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }
        // Averaging
        public static void Averaging(WriteableBitmap image)
        {
            const int halfHeight = 1;
            const int halfWidth = 1;
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = halfHeight; i < image.PixelHeight - halfHeight; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - halfHeight)));
                for (var j = halfWidth; j < image.PixelWidth - halfWidth; j++)
                {
                    var r = 0;
                    var g = 0;
                    var b = 0;
                    for (var k = i - halfHeight; k <= i + halfHeight; k++)
                    {
                        for (var n = j - halfWidth; n <= j + halfWidth; n++)
                        {
                            r += (int)((1/9.0)*
                                 pixels[k*image.PixelWidth*Plen + n*Plen]);
                            g += (int)((1/9.0)*
                                 pixels[k*image.PixelWidth*Plen + n*Plen + 1]);
                            b += (int)((1/9.0)*
                                 pixels[k*image.PixelWidth*Plen + n*Plen + 2]);
                        }
                    }
                    pixelsResult[i*image.PixelWidth*Plen + j*Plen] = (byte) Math.Max(0, Math.Min(255, r));
                    pixelsResult[i*image.PixelWidth*Plen + j*Plen + 1] = (byte) Math.Max(0, Math.Min(255, g));
                    pixelsResult[i*image.PixelWidth*Plen + j*Plen + 2] = (byte) Math.Max(0, Math.Min(255, b));
                }

            }


            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult, image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        public static void Median2D(WriteableBitmap image, byte constant)
        {
            var min = Math.Min(image.PixelHeight, image.PixelWidth);
            if (constant>min)
            {
                MessageBox.Show(String.Format("Вы ввели склишком большую константу. Размер изображения{0}x{1}",
                                              image.PixelHeight, image.PixelWidth));
                return;
            }
            var halfHeight = constant / 2;
            var halfWidth = constant / 2;
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = halfHeight; i < image.PixelHeight - halfHeight; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - halfHeight)));
                for (var j = halfWidth; j < image.PixelWidth - halfWidth; j++)
                {
                
                    var window = new List<Pixel>();
                    for (var k = i - halfHeight; k <= i + halfHeight; k++)
                    {
                        for (var n = j - halfWidth; n <= j + halfWidth; n++)
                        {
                            var r = pixels[k * image.PixelWidth * Plen + n * Plen];
                            var g = pixels[k * image.PixelWidth * Plen + n * Plen + 1];
                            var b = pixels[k * image.PixelWidth * Plen + n * Plen + 2];
                            var a = pixels[k * image.PixelWidth * Plen + n * Plen + 2];
                            window.Add(new Pixel {a = a,b=b,g=g,r=r});
                        }
                    }
                    window.Sort();
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)window[window.Count / 2].r;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)window[window.Count / 2].g;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)window[window.Count / 2].b;
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult, image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        public static void Rank(WriteableBitmap image, int windowSize, int rank)
        {
            rank--;
            var halfHeight = windowSize / 2;
            var halfWidth = windowSize / 2;
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = halfHeight; i < image.PixelHeight - halfHeight; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - halfHeight)));
                for (var j = halfWidth; j < image.PixelWidth - halfWidth; j++)
                {

                    var window = new List<Pixel>();
                    for (var k = i - halfHeight; k <= i + halfHeight; k++)
                    {
                        for (var n = j - halfWidth; n <= j + halfWidth; n++)
                        {
                            var r = pixels[k * image.PixelWidth * Plen + n * Plen];
                            var g = pixels[k * image.PixelWidth * Plen + n * Plen + 1];
                            var b = pixels[k * image.PixelWidth * Plen + n * Plen + 2];
                            var a = pixels[k * image.PixelWidth * Plen + n * Plen + 2];
                            window.Add(new Pixel { a = a, b = b, g = g, r = r });
                        }
                    }
                    window.Sort();
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)window[rank].r;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)window[rank].g;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)window[rank].b;
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult, image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        
    }
    
}
